{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "collapsed": true,
    "executionInfo": {
     "elapsed": 6608,
     "status": "ok",
     "timestamp": 1728007316300,
     "user": {
      "displayName": "Hoyt Long",
      "userId": "07552314465936486693"
     },
     "user_tz": 300
    },
    "id": "ssKxHWSOU6Si",
    "jupyter": {
     "outputs_hidden": true
    },
    "outputId": "2edf6c95-2c6d-4049-8194-d13fc8ae1671"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting openai\n",
      "  Downloading openai-1.51.0-py3-none-any.whl.metadata (24 kB)\n",
      "Requirement already satisfied: anyio<5,>=3.5.0 in /usr/local/lib/python3.10/dist-packages (from openai) (3.7.1)\n",
      "Requirement already satisfied: distro<2,>=1.7.0 in /usr/lib/python3/dist-packages (from openai) (1.7.0)\n",
      "Collecting httpx<1,>=0.23.0 (from openai)\n",
      "  Downloading httpx-0.27.2-py3-none-any.whl.metadata (7.1 kB)\n",
      "Collecting jiter<1,>=0.4.0 (from openai)\n",
      "  Downloading jiter-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (3.6 kB)\n",
      "Requirement already satisfied: pydantic<3,>=1.9.0 in /usr/local/lib/python3.10/dist-packages (from openai) (2.9.2)\n",
      "Requirement already satisfied: sniffio in /usr/local/lib/python3.10/dist-packages (from openai) (1.3.1)\n",
      "Requirement already satisfied: tqdm>4 in /usr/local/lib/python3.10/dist-packages (from openai) (4.66.5)\n",
      "Requirement already satisfied: typing-extensions<5,>=4.11 in /usr/local/lib/python3.10/dist-packages (from openai) (4.12.2)\n",
      "Requirement already satisfied: idna>=2.8 in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3.5.0->openai) (3.10)\n",
      "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<5,>=3.5.0->openai) (1.2.2)\n",
      "Requirement already satisfied: certifi in /usr/local/lib/python3.10/dist-packages (from httpx<1,>=0.23.0->openai) (2024.8.30)\n",
      "Collecting httpcore==1.* (from httpx<1,>=0.23.0->openai)\n",
      "  Downloading httpcore-1.0.6-py3-none-any.whl.metadata (21 kB)\n",
      "Collecting h11<0.15,>=0.13 (from httpcore==1.*->httpx<1,>=0.23.0->openai)\n",
      "  Downloading h11-0.14.0-py3-none-any.whl.metadata (8.2 kB)\n",
      "Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1.9.0->openai) (0.7.0)\n",
      "Requirement already satisfied: pydantic-core==2.23.4 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=1.9.0->openai) (2.23.4)\n",
      "Downloading openai-1.51.0-py3-none-any.whl (383 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m383.5/383.5 kB\u001b[0m \u001b[31m26.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hDownloading httpx-0.27.2-py3-none-any.whl (76 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m76.4/76.4 kB\u001b[0m \u001b[31m7.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hDownloading httpcore-1.0.6-py3-none-any.whl (78 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m78.0/78.0 kB\u001b[0m \u001b[31m7.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hDownloading jiter-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (318 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m318.9/318.9 kB\u001b[0m \u001b[31m27.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hDownloading h11-0.14.0-py3-none-any.whl (58 kB)\n",
      "\u001b[2K   \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m58.3/58.3 kB\u001b[0m \u001b[31m5.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
      "\u001b[?25hInstalling collected packages: jiter, h11, httpcore, httpx, openai\n",
      "Successfully installed h11-0.14.0 httpcore-1.0.6 httpx-0.27.2 jiter-0.5.0 openai-1.51.0\n"
     ]
    }
   ],
   "source": [
    "#load necessary libraries\n",
    "!pip install openai\n",
    "\n",
    "from google.colab import userdata\n",
    "api_key = userdata.get('OPENAI_API_KEY')\n",
    "\n",
    "from openai import OpenAI\n",
    "client = OpenAI(api_key = api_key,)\n",
    "\n",
    "#load functions for each prompt\n",
    "def prompt_1(passage):\n",
    "  #prompt 1\n",
    "  system_prompt = \"You are an experienced writer and teacher of creative writing who has read most of the major creative writing handbooks published over the last fifty years. You are especially good at giving advice on character development in fiction. Character development refers to any aspect of how the author imagines, describes, represents, and enacts the character(s).\"\n",
    "  user_prompt = \"Hi! I'm working on a story and would like some advice on how well I'm handling my character development. Can you identify 2 specific aspects or techniques of character development that I'm using in the passage? For each, please offer some general advice about it's importance for writing good fiction, like what I might find in a creative writing guide. Don't reference my own story in your response. Okay, here's what I've written so far: \"\n",
    "\n",
    "  response = client.chat.completions.create(\n",
    "    model=\"gpt-4o-2024-08-06\",\n",
    "    messages=[\n",
    "      {\n",
    "        \"role\": \"system\",\n",
    "        \"content\": [\n",
    "          {\n",
    "            \"type\": \"text\",\n",
    "            \"text\": system_prompt\n",
    "          }\n",
    "        ]\n",
    "      },\n",
    "      {\n",
    "        \"role\": \"user\",\n",
    "        \"content\": [\n",
    "          {\n",
    "            \"type\": \"text\",\n",
    "            \"text\": user_prompt + passage\n",
    "          }\n",
    "        ]\n",
    "      },\n",
    "    ],\n",
    "    temperature=1,\n",
    "    max_tokens=3000,\n",
    "    top_p=1,\n",
    "    frequency_penalty=0,\n",
    "    presence_penalty=0,\n",
    "    response_format={\n",
    "      \"type\": \"json_schema\",\n",
    "      \"json_schema\": {\n",
    "        \"name\": \"observation_schema\",\n",
    "        \"strict\": True,\n",
    "        \"schema\": {\n",
    "          \"type\": \"object\",\n",
    "          \"properties\": {\n",
    "            \"observations\": {\n",
    "              \"type\": \"array\",\n",
    "              \"items\": {\n",
    "                \"type\": \"object\",\n",
    "                \"properties\": {\n",
    "                  \"technique one\":{\n",
    "                      \"type\": \"string\",\n",
    "                      \"description\": \"Label describing first technique.\"\n",
    "                  },\n",
    "                  \"advice one\": {\n",
    "                    \"type\": \"string\",\n",
    "                    \"description\": \"General advice about technique one.\"\n",
    "                  },\n",
    "                  \"technique two\": {\n",
    "                    \"type\": \"string\",\n",
    "                    \"description\": \"Label describing second technique.\"\n",
    "                  },\n",
    "                  \"advice two\": {\n",
    "                    \"type\": \"string\",\n",
    "                    \"description\": \"General advice about technique two.\"\n",
    "                  }\n",
    "                },\n",
    "                \"required\": [\"technique one\", \"advice one\", \"technique two\", \"advice two\"],\n",
    "                \"additionalProperties\": False\n",
    "              }\n",
    "            }\n",
    "          },\n",
    "          \"required\": [\"observations\"],\n",
    "          \"additionalProperties\": False\n",
    "        }\n",
    "      }\n",
    "    }\n",
    "  )\n",
    "\n",
    "  #return the response text\n",
    "  return response.choices[0].message.content\n",
    "\n",
    "def prompt_2(passage):\n",
    "  #prompt 2\n",
    "  system_prompt = \"You are an experienced writer and teacher of creative writing who has read most of the major creative writing handbooks published over the last fifty years. You are especially good at giving advice on character development in fiction. Character development refers to any aspect of how the author imagines, describes, represents, and enacts the character(s).\"\n",
    "  user_prompt = \"Hi! I'm working on a story and would like some advice on how well I'm handling my character development. Can you rank this passage on a scale of 1 to 10? 1 would mean that I've done a really poor job of characterization, and show little skill at using even the most basic techniques. 10 means the character development is very skilled, showing a high level of fluency with characterization techniques. Just give me a score. Please be as honest as possible in your assessment. Don't offer any written justification yet. Here's what I've written so far: \"\n",
    "\n",
    "  response = client.chat.completions.create(\n",
    "    model=\"gpt-4o-2024-08-06\",\n",
    "    messages=[\n",
    "      {\n",
    "        \"role\": \"system\",\n",
    "        \"content\": [\n",
    "          {\n",
    "            \"type\": \"text\",\n",
    "            \"text\": system_prompt\n",
    "          }\n",
    "        ]\n",
    "      },\n",
    "      {\n",
    "        \"role\": \"user\",\n",
    "        \"content\": [\n",
    "          {\n",
    "            \"type\": \"text\",\n",
    "            \"text\": user_prompt + passage\n",
    "          }\n",
    "        ]\n",
    "      },\n",
    "    ],\n",
    "    temperature=1,\n",
    "    max_tokens=3000,\n",
    "    top_p=1,\n",
    "    frequency_penalty=0,\n",
    "    presence_penalty=0,\n",
    "    response_format={\n",
    "      \"type\": \"text\"\n",
    "    }\n",
    "  )\n",
    "\n",
    "  #return the output text\n",
    "  return response.choices[0].message.content\n",
    "\n",
    "def prompt_3(passage, score):\n",
    "  #prompt 3\n",
    "  system_prompt = \"You are an experienced writer and teacher of creative writing who has read most of the major creative writing handbooks published over the last fifty years. You are especially good at giving advice on character development in fiction. Character development refers to any aspect of how the author imagines, describes, represents, and enacts the character(s).\"\n",
    "  user_prompt = \"I'm a writer working on a new story and want your thoughts on how I'm handling my character development. I previously showed you this passage: \" + passage + \"When I asked you to rank the quality of characterization from 1 to 10, you gave it the following score: \" + score + \"Now I want to know if you have any practical lessons for what I can do as a writer to give my characters complexity and depth? Not on the page, but in my creative process or in how I observe people in the world. Please recommend one exercise I can do and any words of wisdom based on your reaction to the quality of my writing. Please be honest with me.\"\n",
    "\n",
    "  response = client.chat.completions.create(\n",
    "    model=\"gpt-4o-2024-08-06\",\n",
    "    messages=[\n",
    "      {\n",
    "        \"role\": \"system\",\n",
    "        \"content\": [\n",
    "          {\n",
    "            \"type\": \"text\",\n",
    "            \"text\": system_prompt\n",
    "          }\n",
    "        ]\n",
    "      },\n",
    "      {\n",
    "        \"role\": \"user\",\n",
    "        \"content\": [\n",
    "          {\n",
    "            \"type\": \"text\",\n",
    "            \"text\": user_prompt\n",
    "          }\n",
    "        ]\n",
    "      },\n",
    "    ],\n",
    "    temperature=1,\n",
    "    max_tokens=4000,\n",
    "    top_p=1,\n",
    "    frequency_penalty=0,\n",
    "    presence_penalty=0,\n",
    "    response_format={\n",
    "      \"type\": \"json_schema\",\n",
    "      \"json_schema\": {\n",
    "        \"name\": \"reaction_schema\",\n",
    "        \"strict\": True,\n",
    "        \"schema\": {\n",
    "          \"type\": \"object\",\n",
    "          \"properties\": {\n",
    "            \"reaction\": {\n",
    "              \"type\": \"array\",\n",
    "              \"items\": {\n",
    "                \"type\": \"object\",\n",
    "                \"properties\": {\n",
    "                  \"exercise\":{\n",
    "                      \"type\": \"string\",\n",
    "                      \"description\": \"A practical, real-world exercise to improve characterization.\"\n",
    "                  },\n",
    "                  \"wisdom\": {\n",
    "                    \"type\": \"string\",\n",
    "                    \"description\": \"Words of wisdom based on honest assessment of my writing.\"\n",
    "                  }\n",
    "                },\n",
    "                \"required\": [\"exercise\", \"wisdom\"],\n",
    "                \"additionalProperties\": False\n",
    "              }\n",
    "            }\n",
    "          },\n",
    "          \"required\": [\"reaction\"],\n",
    "          \"additionalProperties\": False\n",
    "        }\n",
    "      }\n",
    "    }\n",
    "  )\n",
    "\n",
    "  #return the output text\n",
    "  return response.choices[0].message.content\n",
    "\n",
    "def prompt_4(passage, observations):\n",
    "  #prompt 4\n",
    "  system_prompt = \"You are an experienced writer and teacher of creative writing who has read most of the major creative writing handbooks published over the last fifty years. You are especially good at giving advice on character development in fiction. Character development refers to any aspect of how the author imagines, describes, represents, and enacts the character(s).\"\n",
    "  user_prompt = \"I'm a writer working on a story and you previously observed the following about a passage I showed you: \" + observations + \" What's the first and best piece of actionable advice you think I need to improve my characterization? Do not revise or rewrite the passage. Just give me one actionable item and a written explanation in 300 words or less. If you know of a relevant example from a novel or published story, please share it. Here's the passage I showed you before: \"\n",
    "\n",
    "  response = client.chat.completions.create(\n",
    "    model=\"gpt-4o-2024-08-06\",\n",
    "    messages=[\n",
    "      {\n",
    "        \"role\": \"system\",\n",
    "        \"content\": [\n",
    "          {\n",
    "            \"type\": \"text\",\n",
    "            \"text\": system_prompt\n",
    "          }\n",
    "        ]\n",
    "      },\n",
    "      {\n",
    "        \"role\": \"user\",\n",
    "        \"content\": [\n",
    "          {\n",
    "            \"type\": \"text\",\n",
    "            \"text\": user_prompt + passage\n",
    "          }\n",
    "        ]\n",
    "      },\n",
    "    ],\n",
    "    temperature=1,\n",
    "    max_tokens=4000,\n",
    "    top_p=1,\n",
    "    frequency_penalty=0,\n",
    "    presence_penalty=0,\n",
    "    response_format={\n",
    "      \"type\": \"json_schema\",\n",
    "      \"json_schema\": {\n",
    "        \"name\": \"feedback_schema\",\n",
    "        \"strict\": True,\n",
    "        \"schema\": {\n",
    "          \"type\": \"object\",\n",
    "          \"properties\": {\n",
    "            \"steps\": {\n",
    "              \"type\": \"array\",\n",
    "              \"items\": {\n",
    "                \"type\": \"object\",\n",
    "                \"properties\": {\n",
    "                  \"label\":{\n",
    "                      \"type\": \"string\",\n",
    "                      \"description\": \"Simple label to categorize the actionable advice.\"\n",
    "                  },\n",
    "                  \"actionable advice\": {\n",
    "                    \"type\": \"string\"\n",
    "                  },\n",
    "                  \"explanation\": {\n",
    "                    \"type\": \"string\",\n",
    "                    \"description\": \"A 300 word explanation of the given advice.\"\n",
    "                  },\n",
    "                  \"example\": {\n",
    "                    \"type\": \"string\",\n",
    "                    \"description\": \"A relevant example from another novel or published story.\"\n",
    "                  }\n",
    "                },\n",
    "                \"required\": [\"label\", \"actionable advice\", \"explanation\", \"example\"],\n",
    "                \"additionalProperties\": False\n",
    "              }\n",
    "            }\n",
    "          },\n",
    "          \"required\": [\"steps\"],\n",
    "          \"additionalProperties\": False\n",
    "        }\n",
    "      }\n",
    "    }\n",
    "  )\n",
    "\n",
    "  #return the output\n",
    "  return response.choices[0].message.content\n",
    "\n",
    "def prompt_5(passage, feedback):\n",
    "  #prompt 5\n",
    "  system_prompt = \"You are an experienced writer and teacher of creative writing who has read most of the major creative writing handbooks published over the last fifty years. You are especially good at giving advice on character development in fiction. Character development refers to any aspect of how the author imagines, describes, represents, and enacts the character(s).\"\n",
    "  user_prompt = \"I'm a writer working on a story and you previously gave me the following feedback about a passage I showed you: \" + feedback + \"Using this feedback, can you rewrite the passage for me? Do not change things that you think are working well. And please just return the revised passage, without additional explanation. Here's the passage again: \"\n",
    "\n",
    "  response = client.chat.completions.create(\n",
    "    model=\"gpt-4o-2024-08-06\",\n",
    "    messages=[\n",
    "      {\n",
    "        \"role\": \"system\",\n",
    "        \"content\": [\n",
    "          {\n",
    "            \"type\": \"text\",\n",
    "            \"text\": system_prompt\n",
    "          }\n",
    "        ]\n",
    "      },\n",
    "      {\n",
    "        \"role\": \"user\",\n",
    "        \"content\": [\n",
    "          {\n",
    "            \"type\": \"text\",\n",
    "            \"text\": user_prompt + '\\n' + passage\n",
    "          }\n",
    "        ]\n",
    "      },\n",
    "    ],\n",
    "    temperature=1,\n",
    "    max_tokens=4000,\n",
    "    top_p=1,\n",
    "    frequency_penalty=0,\n",
    "    presence_penalty=0,\n",
    "    response_format={\n",
    "      \"type\": \"text\"\n",
    "    }\n",
    "  )\n",
    "\n",
    "  #return output text\n",
    "  return response.choices[0].message.content"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "2NCEc9ZoUncg"
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import random\n",
    "import time\n",
    "\n",
    "#import dataframe containing all the passages\n",
    "#need to load this csv file into Colab\n",
    "df = pd.read_csv(\"/content/drive/MyDrive/AI_Instructor/MASTER_META.csv\")\n",
    "\n",
    "# Generate 10 random numbers between 1 and 800\n",
    "#rows_to_filter = random.sample(range(1, 801), 10)\n",
    "# Filter the DataFrame based on the random numbers\n",
    "#df = df.iloc[rows_to_filter]\n",
    "\n",
    "# Create new columns in the DataFrame\n",
    "df[\"OBSERVATIONS\"] = \"\"\n",
    "df[\"SCORE\"] = \"\"\n",
    "df[\"REACTION\"] = \"\"\n",
    "df[\"FEEDBACK\"] = \"\"\n",
    "df[\"REVISED_PASSAGE\"] = \"\"\n",
    "\n",
    "#loop through dataframe and feed passages into prompts\n",
    "for k in df.index:\n",
    "  #get the passage\n",
    "  passage = df.loc[k, \"PASSAGE\"]\n",
    "\n",
    "  #move through prompts\n",
    "  #insert a .12 second pause between calls to API (we have 500 RPM limit)\n",
    "  observations = prompt_1(passage)\n",
    "  time.sleep(.12)\n",
    "  score = prompt_2(passage)\n",
    "  time.sleep(.12)\n",
    "  reaction = prompt_3(passage, score)\n",
    "  time.sleep(.12)\n",
    "  feedback = prompt_4(passage, observations)\n",
    "  time.sleep(.12)\n",
    "  revised_passage = prompt_5(passage, feedback)\n",
    "  time.sleep(.12)\n",
    "\n",
    "  df.loc[k, \"OBSERVATIONS\"] = observations\n",
    "  df.loc[k, \"SCORE\"] = score\n",
    "  df.loc[k, \"REACTION\"] = reaction\n",
    "  df.loc[k, \"FEEDBACK\"] = feedback\n",
    "  df.loc[k, \"REVISED_PASSAGE\"] = revised_passage\n",
    "\n",
    "  #we might also want to save output text in case we hit a runtime error (or just write .csv to disk at certain intervals?)\n",
    "\n",
    "# save the dataframe to disk\n",
    "df.to_csv('/content/drive/MyDrive/AI_Instructor/GPT_OUTPUT.csv', index=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "collapsed": true,
    "executionInfo": {
     "elapsed": 280,
     "status": "ok",
     "timestamp": 1727031873695,
     "user": {
      "displayName": "Hoyt Long",
      "userId": "07552314465936486693"
     },
     "user_tz": 300
    },
    "id": "UZtJzY8eF7wy",
    "jupyter": {
     "outputs_hidden": true
    },
    "outputId": "76387a70-8adf-4f31-ad2f-1c934e67e861"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(799, 13)"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# save the dataframe to disk\n",
    "#df.to_csv('MASTER_META_OUTPUT.csv', index=False)\n",
    "df.shape"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.19"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
